/*
	MIDAS Context Based Routing
	cbr_compressor.cc
	Copyright (c) 2007 Radoslaw Olgierd Schoeneich
	MEAG IT PW
*/

#include "cbr_config.h"
#include "cbr_compressor.h"
#include "cbr_crt.h"

extern bool local_context_model;

/**
 * Reduce CBR Hello message size by using compression.
 *
 * @param list CBR triples list
 * @param model CBR context model
 *
 * Traverses CBR triples list @a list to find two CBR triples representing
 * concepts which share the maximum number of common super-concepts, then
 * it replaces two found CBR triples with the new CBR triple which represents
 * the common super-concept.
 *
 * @return number of bytes gained by using compression.
 */

int cbr_Compressor::reduce(cbr_TriplesList& list,const cbr_ContextModel& model)
{
	cbr_TriplesList::iterator i, j;
	cbr_TriplesList::iterator cand1, cand2;
	int cnt, highest_common_count = -1;
	int saving = 0;

	for (i = list.begin(); i != list.end(); i++) {
		for (j = list.begin(); j != list.end(); j++) {
			if (i == j)
				continue;
			cnt = model.getCommonSuperClassesCount((*i)->getConcept(), (*j)->getConcept());
			if (cnt > highest_common_count) {
				highest_common_count = cnt;
				cand1 = i;
				cand2 = j;
			}
		}
	}

	cbr_debug("reducing '%s' and '%s'\n", (*cand1)->getConcept().c_str(), (*cand2)->getConcept().c_str());
	saving = (*cand1)->getByteLength() + (*cand2)->getByteLength();
	cbr_Triple* t = new cbr_Triple(*(*cand1), *(*cand2), &model);
	cbr_debug(" closest common concept: '%s'\n", t->getConcept().c_str());
	if (t->getConcept() != "Thing") {
		saving -= t->getByteLength();
		list.push_back(t);
	} else {
		delete t;
	}

	delete *cand1; list.erase(cand1);
	delete *cand2; list.erase(cand2);

	return saving;
}

/**
 * Compress CBR Hello message size.
 *
 * @param list CBR triples list
 * @param model CBR context model
 * @param max_length maximum allowed message size
 *
 * Compress CBR Hello message size until its size is less
 * than or equal to the maximum allowed message size.
 *
 * @return compressed message size.
 */

int cbr_Compressor::compress(cbr_TriplesList& list,
			const cbr_ContextModel& model,
			int max_length)
{
	cbr_TriplesList::const_iterator i;
	int curr_length = 0;

	for (i = list.begin(); i != list.end(); i++)
		curr_length += (*i)->getByteLength();

	while (curr_length > max_length) {
		curr_length -= reduce(list, model);
	}

	return curr_length;
}
